import logging
from datetime import datetime
from typing import List, Optional

from sqlalchemy import select

from app.admin.db import role_crud, resource_crud
from app.admin.schemas.resource import ResourceCreate, ResourceUpdate
from app.admin.schemas.role import RoleCreate, RoleUpdate
from app.db.session import AsyncSessionLocal
from app.models.resource import Resource
from app.models.role import Role, user_role, role_resource
from app.models.user import User
from app.utils.date_utils import get_current_time
from app.utils.str_utils import generate_uuid_without_hyphen

# 配置日志
logger = logging.getLogger(__name__)


class RoleService:
    """
    角色服务类，处理角色相关的业务逻辑
    """

    async def create_role(self, role: RoleCreate) -> Role:
        """创建角色"""
        role.id = generate_uuid_without_hyphen()
        role.created_at = get_current_time()
        role.updated_at = role.created_at

        async with AsyncSessionLocal() as db:
            return await role_crud.create_role(db, role)

    async def get_role(self, role_id: str, tenant_id: str = None) -> Optional[Role]:
        """根据ID获取角色"""
        async with AsyncSessionLocal() as db:
            return await role_crud.get_role(db, role_id, tenant_id)

    async def get_role_by_name(self, name: str, tenant_id: str = None) -> Optional[Role]:
        """根据名称获取角色"""
        async with AsyncSessionLocal() as db:
            return await role_crud.get_role_by_name(db, name, tenant_id)

    async def get_roles(self, skip: int = 0, limit: int = 100, tenant_id: str = None) -> List[Role]:
        """获取角色列表"""
        async with AsyncSessionLocal() as db:
            return await role_crud.get_roles(db, skip=skip, limit=limit, tenant_id=tenant_id)

    async def update_role(self, role_id: str, role_update: RoleUpdate) -> Optional[Role]:
        """更新角色"""
        # 设置更新时间
        role_update_dict = role_update.dict(exclude_unset=True)
        role_update_dict["updated_at"] = datetime.now()
        role_update = RoleUpdate(**role_update_dict)

        async with AsyncSessionLocal() as db:
            return await role_crud.update_role(db, role_id, role_update)

    async def delete_role(self, role_id: str, tenant_id: str = None) -> bool:
        """删除角色"""
        async with AsyncSessionLocal() as db:
            return await role_crud.delete_role(db, role_id, tenant_id)

    async def assign_roles_to_user(self, user_id: str, role_ids: List[str], tenant_id: str = None) -> bool:
        """为用户分配角色"""
        async with AsyncSessionLocal() as db:
            return await role_crud.assign_roles_to_user(db, user_id, role_ids, tenant_id)

    async def assign_users_to_role(self, role_id: str, user_ids: List[str], tenant_id: str = None) -> bool:
        """为角色分配用户"""
        async with AsyncSessionLocal() as db:
            return await role_crud.assign_users_to_role(db, role_id, user_ids, tenant_id)

    async def get_user_roles(self, user_id: str, tenant_id: str = None) -> List[Role]:
        """获取用户的角色列表"""
        async with AsyncSessionLocal() as db:
            return await role_crud.get_user_roles(db, user_id, tenant_id)

    async def get_role_users(self, role_id: str, tenant_id: str = None) -> List[User]:
        """
        获取角色的用户列表
        """
        async with AsyncSessionLocal() as db:
            # 使用显式查询获取角色的用户列表
            if tenant_id:
                stmt = select(User).join(user_role).where(
                    user_role.c.role_id == role_id,
                    User.tenant_id == tenant_id
                )
            else:
                stmt = select(User).join(user_role).where(user_role.c.role_id == role_id)

            result = await db.execute(stmt)
            users = result.scalars().all()
            return users

    async def remove_user_roles(self, user_id: str, role_ids: List[str], tenant_id: str = None) -> bool:
        """移除用户的角色"""
        async with AsyncSessionLocal() as db:
            return await role_crud.remove_user_roles(db, user_id, role_ids, tenant_id)

    async def check_role_exists(self, name: str, tenant_id: str = None) -> bool:
        """检查角色名称是否存在"""
        async with AsyncSessionLocal() as db:
            return await role_crud.check_role_exists(db, name, tenant_id)

    async def set_role_resource(self, role_id: str, resource_ids: List[str], tenant_id: str = None) -> bool:
        """
        为角色设置资源（会覆盖原有角色）
        """
        async with AsyncSessionLocal() as db:
            # 获取角色
            if tenant_id:
                stmt = select(Role).where(Role.id == role_id, Role.tenant_id == tenant_id)
            else:
                stmt = select(Role).where(Role.id == role_id)

            result = await db.execute(stmt)
            role = result.scalar_one_or_none()
            if not role:
                logger.warning(f"设置角色资源失败: 角色 [{role_id}] 不存在")
                return False

            # 获取资源
            if resource_ids:
                stmt = select(Resource).where(Resource.id.in_(resource_ids))
                result = await db.execute(stmt)
                resources = result.scalars().all()

                # 检查是否有不存在的资源
                if len(resources) != len(resource_ids):
                    logger.warning(f"设置角色资源失败: 部分资源不存在")
                    return False
            else:
                resources = []

            # 设置角色资源（会覆盖原有资源）
            role.resources = resources
            role.updated_at = datetime.now()

            await db.commit()
            await db.refresh(role)
            logger.info(f"角色 [{role_id}] 资源设置成功")
            return True

# 创建全局角色服务实例
role_service = RoleService()
